"""
示例厂商PLC客户端模块

这是一个示例模块，展示如何为新的PLC厂商添加支持
复制此文件并根据实际设备修改即可
"""

import logging
from typing import List, Optional
from pymodbus.client import ModbusTcpClient
from pymodbus.exceptions import ModbusException, ConnectionException

from .base import BasePLCClient

logger = logging.getLogger(__name__)


class ExampleVendorPLCClient(BasePLCClient):
    """示例厂商PLC客户端 - 请根据实际设备修改"""
    
    def __init__(self, host="127.0.0.1", port=502, timeout=3.0, slave_id=1):
        """
        初始化示例厂商PLC客户端
        
        参数:
            host (str): PLC的IP地址
            port (int): Modbus TCP端口
            timeout (float): 通信超时时间
            slave_id (int): 从站地址
        """
        super().__init__()
        self.host = host
        self.port = port
        self.timeout = timeout
        self.slave_id = slave_id

    def connect(self) -> bool:
        """连接到PLC设备"""
        try:
            self.client = ModbusTcpClient(
                host=self.host,
                port=self.port,
                timeout=self.timeout
            )
            
            if self.client.connect():
                self.connected = True
                logger.info(f"成功连接到示例厂商PLC: {self.host}:{self.port}")
                return True
            else:
                self.connected = False
                logger.error(f"无法连接到示例厂商PLC: {self.host}:{self.port}")
                return False
        except Exception as e:
            self.connected = False
            logger.error(f"示例厂商PLC连接异常: {e}")
            return False

    def close(self) -> None:
        """关闭连接"""
        if self.client:
            self.client.close()
            self.connected = False
            logger.info(f"已关闭与示例厂商PLC的连接: {self.host}:{self.port}")

    def read_registers(self, start_address: int, count: int = 1) -> Optional[List[int]]:
        """
        读取寄存器 - 实现基类的通用接口
        
        参数:
            start_address: 起始地址
            count: 读取数量
            
        返回:
            寄存器值列表或None
        """
        if not self.is_connected():
            logger.error("客户端未连接")
            return None
            
        try:
            result = self.client.read_holding_registers(
                address=start_address,
                count=count,
                slave=self.slave_id
            )
            
            if not result.isError():
                logger.info(f"成功读取寄存器{start_address}: {result.registers}")
                return result.registers
            else:
                logger.error(f"读取寄存器{start_address}失败: {result}")
                return None
                
        except ModbusException as e:
            logger.error(f"Modbus通信错误: {e}")
            return None
        except Exception as e:
            logger.error(f"读取寄存器时发生错误: {e}")
            return None

    def write_registers(self, start_address: int, values: List[int]) -> bool:
        """
        写入寄存器 - 实现基类的通用接口
        
        参数:
            start_address: 起始地址
            values: 要写入的值列表
            
        返回:
            写入成功返回True，失败返回False
        """
        if not self.is_connected():
            logger.error("客户端未连接")
            return False
            
        try:
            result = self.client.write_registers(
                address=start_address,
                values=values,
                slave=self.slave_id
            )
            
            if not result.isError():
                logger.info(f"成功写入寄存器{start_address}: {values}")
                return True
            else:
                logger.error(f"写入寄存器{start_address}失败: {result}")
                return False
                
        except ModbusException as e:
            logger.error(f"Modbus通信错误: {e}")
            return False
        except Exception as e:
            logger.error(f"写入寄存器时发生错误: {e}")
            return False

    def read_coils(self, start_address: int, count: int = 1) -> Optional[List[bool]]:
        """
        读取线圈 - 实现基类的通用接口
        
        参数:
            start_address: 起始地址
            count: 读取数量
            
        返回:
            线圈状态列表或None
        """
        if not self.is_connected():
            logger.error("客户端未连接")
            return None
            
        try:
            result = self.client.read_coils(
                address=start_address,
                count=count,
                slave=self.slave_id
            )
            
            if not result.isError():
                logger.info(f"成功读取线圈{start_address}: {result.bits}")
                return result.bits
            else:
                logger.error(f"读取线圈{start_address}失败: {result}")
                return None
                
        except ModbusException as e:
            logger.error(f"Modbus通信错误: {e}")
            return None
        except Exception as e:
            logger.error(f"读取线圈时发生错误: {e}")
            return None

    def write_coils(self, start_address: int, values: List[bool]) -> bool:
        """
        写入线圈 - 实现基类的通用接口
        
        参数:
            start_address: 起始地址
            values: 要写入的状态列表
            
        返回:
            写入成功返回True，失败返回False
        """
        if not self.is_connected():
            logger.error("客户端未连接")
            return False
            
        try:
            result = self.client.write_coils(
                address=start_address,
                values=values,
                slave=self.slave_id
            )
            
            if not result.isError():
                logger.info(f"成功写入线圈{start_address}: {values}")
                return True
            else:
                logger.error(f"写入线圈{start_address}失败: {result}")
                return False
                
        except ModbusException as e:
            logger.error(f"Modbus通信错误: {e}")
            return False
        except Exception as e:
            logger.error(f"写入线圈时发生错误: {e}")
            return False

    def test_connection(self) -> bool:
        """测试连接"""
        if not self.is_connected():
            logger.error("客户端未连接，无法进行测试")
            return False
            
        # 尝试读取地址0，这通常是最基本的测试
        try:
            result = self.client.read_holding_registers(address=0, count=1, slave=self.slave_id)
            if not result.isError():
                logger.info(f"连接测试成功！地址0返回: {result.registers}")
                return True
            else:
                logger.warning(f"连接测试失败: {result}")
                return False
        except Exception as e:
            logger.error(f"连接测试异常: {e}")
            return False

    def get_device_info(self) -> dict:
        """获取设备信息"""
        info = super().get_device_info()
        info.update({
            "manufacturer": "示例厂商",
            "model": "示例型号",
            "communication": "Modbus TCP",
            "host": self.host,
            "port": self.port,
            "slave_id": self.slave_id
        })
        return info


# 添加新厂商时，需要在factory.py中注册：
"""
在 factory.py 的 clients 字典中添加：
"example_vendor_tcp": ExampleVendorPLCClient,

在 get_supported_devices() 函数中添加：
"example_vendor_tcp": {
    "manufacturer": "示例厂商 (Example Vendor)",
    "model": "示例型号",
    "communication": "Modbus TCP",
    "description": "示例厂商PLC设备，通过以太网进行Modbus TCP通信",
    "parameters": ["host", "port", "timeout", "slave_id"]
}
"""
